////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "WNScripting/inc/WNInteropSimpleIO.h"
#include "WNScripting/inc/WNInteropHelpers.h"
#include "WNStrings/inc/WNStrings.h"
#include "WNMemory/inc/WNMemory.h"

using namespace WNMemory;

WN_VOID WNInterop::WNWriteString(WN_BYTE* _scriptString) {
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_scriptString);
    WN_SIZE_T stringLength = stringArray.Length();
    WN_CHAR* copyTo = static_cast<WN_CHAR*>(WN_STACK_ALLOC(stringLength + 1));
    WNMemCpy(copyTo, &stringArray[0], stringLength);
    copyTo[stringLength] = '\0';
    WN_PRINTF("%s", copyTo);
}

WN_VOID WNInterop::WNWriteString2(WN_BYTE* _scriptString, WN_INT32 _length) {
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_scriptString);
    WN_SIZE_T stringLength = stringArray.Length();
    WN_SIZE_T copyLen = (static_cast<WN_SIZE_T>(_length) < stringLength)? _length : stringLength;

    WN_CHAR* copyTo = static_cast<WN_CHAR*>(WN_STACK_ALLOC(copyLen + 1));
    WNMemCpy(copyTo, &stringArray[0], copyLen);
    copyTo[copyLen] = '\0';
    WN_PRINTF("%s", copyTo);
}

WN_INT32 WNInterop::WNStackReadLine(WN_INT32 _maxSize) {
    WN_CHAR* charArray = static_cast<WN_CHAR*>(WN_STACK_ALLOC(_maxSize));
    WN_INT32 copied = 0;
    for(copied = 0; copied < _maxSize; ++copied) {
        int ch = getchar();
        if( ch == '\n') {
            charArray[copied] = ch;
            copied += 1;
            break;
        } else if (ch == EOF) {
            break;
        }
        charArray[copied] = ch;
    }
    WNScriptInterop::ScriptArray<WN_CHAR> array = WNScriptInterop::CreateScriptArrayForStack<WN_CHAR>(copied);
    WNMemCpy(&array[0], charArray, copied);
    return(array.GetSizeInBytes());
}

WN_INT32 WNInterop::WNReadLine(WN_BYTE* _scriptString) {
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_scriptString);
    WN_SIZE_T stringLength = stringArray.Length();
    WN_INT32 copied = 0;
    for(copied = 0; copied < static_cast<WN_INT32>(stringLength); ++copied) {
        int ch = getchar();
        if( ch == '\n') {
            stringArray[copied] = ch;
            copied += 1;
            break;
        } else if (ch == EOF) {
            break;
        }
        stringArray[copied] = ch;
    }
    return(copied);
}

WN_INT32 WNInterop::WNAppend0(WN_BYTE* _string, WN_INT32 _buffLoc, WN_INT32 _number) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_string);
    WN_SIZE_T stringLength = stringArray.Length();
    WN_INT32 retVal = WN_SNPRINTF(&stringArray[_buffLoc], stringLength - _buffLoc, "%d", _number);
    return(retVal);
}

WN_INT32 WNInterop::WNAppend1(WN_BYTE* _string, WN_INT32 _buffLoc, WN_CHAR _character) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_string);
    WN_SIZE_T stringLength = stringArray.Length();
    if(static_cast<WN_SIZE_T>(_buffLoc) < stringLength) {
        stringArray[_buffLoc++] = _character;
        return(1);
    } else {
        return(0);
    }
}

WN_INT32 WNInterop::WNAppend2(WN_BYTE* _string, WN_INT32 _buffLoc, WN_FLOAT32 _number) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_string);
    WN_SIZE_T stringLength = stringArray.Length();
    WN_INT32 retVal = WN_SNPRINTF(&stringArray[_buffLoc], stringLength - _buffLoc, "%g", _number);
    return(retVal);
}

WN_INT32 WNInterop::WNAppend3(WN_BYTE* _string, WN_INT32 _buffLoc, WN_INT32 _number, WN_INT32 _length) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_string);
    WN_SIZE_T stringLength = stringArray.Length();

    if(static_cast<WN_SIZE_T>(_buffLoc + _length) > stringLength){
        return(0);
    }

    WN_INT32 retVal = WN_SNPRINTF(&stringArray[_buffLoc], stringLength - _buffLoc, "%*d", _length, _number);
    return(retVal);
}

WN_INT32 WNInterop::WNAppend4(WN_BYTE* _string, WN_INT32 _buffLoc, WN_FLOAT32 _number, WN_INT32 _whole, WN_INT32 _fraction) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);

    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_string);
    WN_SIZE_T stringLength = stringArray.Length();

    if(static_cast<WN_SIZE_T>(_buffLoc + _whole + _fraction) > stringLength){
        return(0);
    }

    WN_INT32 retVal = WN_SNPRINTF(&stringArray[_buffLoc], stringLength - _buffLoc, "%*.*f", _whole + _fraction + 1, _fraction, _number);
    return(retVal);
}

WN_INT32 WNInterop::WNAppend5(WN_BYTE* _buff, WN_INT32 _buffLoc, WN_BYTE* _string) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);

    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_buff);
    WN_SIZE_T stringLength = stringArray.Length();
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray2(_string);

    if(static_cast<WN_SIZE_T>(_buffLoc + stringArray2.Length()) > stringLength){
        return(0);
    }
    WNMemCpy(&stringArray[_buffLoc], &stringArray2[0], stringArray2.Length());
    return(static_cast<WN_INT32>(stringArray2.Length()));
}

WN_INT32 WNInterop::WNAppend6(WN_BYTE* _buff, WN_INT32 _buffLoc, WN_BYTE* _string, WN_INT32 _size) {
    WN_DEBUG_ASSERT(_buffLoc >= 0);

    WNScriptInterop::ScriptArray<WN_CHAR> stringArray(_buff);
    WN_SIZE_T stringLength = stringArray.Length();
    WNScriptInterop::ScriptArray<WN_CHAR> stringArray2(_string);
    if(static_cast<WN_SIZE_T>(_buffLoc + _size) > stringLength){
        return(0);
    }

    WN_CHAR* copyTo = static_cast<WN_CHAR*>(WN_STACK_ALLOC(stringArray2.Length() + 1));
    WNMemCpy(copyTo, &stringArray2[0], stringArray2.Length());
    copyTo[stringArray2.Length()] = '\0';

    WN_INT32 retVal = WN_SNPRINTF(&stringArray[_buffLoc], stringLength - _buffLoc, "%*.*s", _size, _size, copyTo);
    return(retVal);
}
